import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;

import com.university.rmi.RemoteObject;

public class RemoteObjectImpl extends UnicastRemoteObject implements RemoteObject {
    protected RemoteObjectImpl() throws RemoteException {

	// TODO Auto-generated constructor stub
    }

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private long[][] pixels;
    private long[][] pixels2;
    private int height;
    private int width;

    // public void setImage(BufferedImage bufImage) {
    // width = bufImage.getWidth();
    // height = bufImage.getHeight();
    // pixels2 = new long[height][width];
    // pixels = oneDArrayToTwoDarray(bufImage.getRGB(0, 0, width, height, null,
    // 0, width));
    // }
    private int getMedian(int[] arr) {
	for (int i = 0; i < arr.length - 1; i++)
	    for (int j = 0; j < arr.length - i - 1; j++)
		if (arr[j] > arr[j + 1]) {
		    int tmp = arr[j];
		    arr[j] = arr[j + 1];
		    arr[j + 1] = tmp;
		}

	return arr[5];
    }

    private int[] twoDArrayToOneDarray(long[][] arr) {
	int[] resArr = new int[height * width];
	for (int i = 0; i < resArr.length; i++) {
	    resArr[i] = (int) arr[(int) (i / width)][i % width];
	}
	return resArr;
    }

    private long[][] oneDArrayToTwoDarray(int[] arr) {
	long[][] resArr = new long[height][width];
	for (int i = 0; i < height; i++) {
	    for (int j = 0; j < width; j++) {
		resArr[i][j] = arr[i * width + j];
	    }
	}
	return resArr;
    }

    @Override
    public byte[] filter(byte[] bytes) throws RemoteException {

	BufferedImage bufImage = null;
	try {
	    bufImage = ImageIO.read( new ByteArrayInputStream(bytes));
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}
	width = bufImage.getWidth();
	height = bufImage.getHeight();
	pixels2 = new long[height][width];
	pixels = oneDArrayToTwoDarray(bufImage.getRGB(0, 0, width, height, null, 0, width));
	int[] filteredArray = new int[9];

	for (int y = 2; y < height - 2; y++) {
	    for (int x = 2; x < width - 2; x++) {

		filteredArray[0] = (int) pixels[y - 2][x];
		filteredArray[1] = (int) pixels[y - 1][x];
		filteredArray[3] = (int) pixels[y + 1][x];
		filteredArray[4] = (int) pixels[y + 2][x];
		filteredArray[2] = (int) pixels[y][x];
		filteredArray[5] = (int) pixels[y][x - 2];
		filteredArray[6] = (int) pixels[y][x - 1];
		filteredArray[7] = (int) pixels[y][x + 1];
		filteredArray[8] = (int) pixels[y][x + 2];

		pixels2[y][x] = getMedian(filteredArray);
	    }

	}

	BufferedImage dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
	dst.setRGB(0, 0, width, height, twoDArrayToOneDarray(pixels2), 0, width);
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	try {
	    ImageIO.write(dst, "PNG", out);
	    out.flush();
	} catch (IOException e) {
	    // TODO Auto-generated catch block
	    e.printStackTrace();
	}

	return out.toByteArray();
    }

}
